package com.welica.wat.aspect;

import java.lang.reflect.Method;
import java.util.Arrays;

import javax.annotation.Resource;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Component;

import com.welica.wat.impl.ZookeeperLock;
import com.welica.wat.stragety.annotation.DistributeLock;

/**
 * @ClassName: DistributeLockAspect
 * @Description: 基于redssion实现分布式锁，AOP切面声明
 * @author weiyongpeng
 * @date 2024年11月1日 下午8:45:29
 */
@Component
@Aspect
@ConditionalOnBean(ZookeeperLock.class)
public class ZookeeperDistributeLockAspect {

	private static final Logger log = LoggerFactory.getLogger(ZookeeperDistributeLockAspect.class);

	@Resource
	private ZookeeperLock distributeLock;

	/**
	 * @annotation 中的路径表示拦截特定注解
	 */
	@Pointcut("@annotation(com.welica.wat.stragety.annotation.DistributeLock)")
	public void lockAop() {
	}

	@Around(value = "lockAop()")
	public Object setDistributeLock(ProceedingJoinPoint pjp) throws Throwable {
		// 解析参数
		Method method = resolveMethod(pjp);
		DistributeLock annotation = method.getAnnotation(DistributeLock.class); // 拦截方法上的注解
		String params = Arrays.toString(pjp.getArgs()); // 获取方法参数
		String lockName = annotation.lockName(); // 获取锁的key
		if (!"[]".equals(params)) {
			// 获取锁
			lockName = annotation.lockName() + "_" + params.replace("[", "").replace("]", "");
		}

		boolean b = distributeLock.lock(lockName, annotation.expireTime(), false);
		if (b) {
			Object ret = pjp.proceed();// 执行业务逻辑
			// 释放锁
			distributeLock.unLock(lockName);
			return ret;
		}
		return null;
	}

	private Method resolveMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {
		Signature sig = pjp.getSignature();
		MethodSignature msig = null;
		if (!(sig instanceof MethodSignature)) {
			throw new IllegalArgumentException("该注解只能用于方法");
		}
		msig = (MethodSignature) sig;
		Object target = pjp.getTarget();
		return target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
	}

}
